package io.acna.mybatis.plugins;


import io.acna.autils.Obj;
import io.acna.mybatis.plugins.core.IndieCondition;
import io.acna.mybatis.plugins.core.enums.ERelation;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Invocation;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

public class QueryCore {

    private boolean isFirst = true;
    private String connecStr = null;
    private String conditionSql = "";
    private String strAnd = "AND";
    private String strWhere = "WHERE";
    private IndieCondition condition;
    private String sqlSource;
    private BoundSql boundSql;
    private ConditionHelper.InterceptorType type;
    final String SPACE = " ";

    public Object queryCondition(Invocation invocation) {
        sqlSource = boundSql.getSql();
        //进入search条件拼装
        if (Obj.notNullOrEmpty(condition.getSearch())) {
            StringBuffer tempSearchSql = new StringBuffer();
            int index = 0;
            int count = condition.getSearch().size();
            for (Map.Entry<Map<String, Object>, ERelation> s : condition.getSearch().entrySet()) {
                String c = s.getValue().getValue();//得到连接符字符串
                for (Map.Entry<String, Object> ss : s.getKey().entrySet()) {
                    if (!Obj.notNullOrEmpty(ss.getValue()))
                        continue;
                    String col = ss.getKey();//得到列名
                    Object val = ss.getValue();//得到值
                    if (val == null)//如果值为空跳过
                        continue;
                    if (s.getValue() == ERelation.LIKE) {//如果是字符串
                        tempSearchSql.append(col + SPACE + c + SPACE + "\"%" + val + "%\"");
                    } else if (val instanceof String) {
                        tempSearchSql.append(col + SPACE + c + SPACE + "\"" + val + "\"");
                    } else {
                        tempSearchSql.append((col + SPACE + c + SPACE + val));
                    }
                    if (index++ != count - 1)
                        tempSearchSql.append(SPACE + strAnd + SPACE);
                }
            }
            buildSql(tempSearchSql.toString());
            isFirst = false;
        }
        //进入between-and拼装
        if (Obj.notNullOrEmpty(condition.getBeteens())) {
            int betweenLength = condition.getBeteens().size();
            int index = 0;
            StringBuffer tempBetwnneSql = new StringBuffer();
            for (Map.Entry<String, Object[]> b : condition.getBeteens().entrySet()) {
                if (!Obj.notNullOrEmpty(b.getValue()) || b.getValue().length < 2)
                    continue;
                Object[] vals = b.getValue();
                String col = b.getKey();
                Object val1 = vals[0];
                Object val2 = vals[1];
                tempBetwnneSql.append(col + SPACE + "BETWEEN" + SPACE + val1 + SPACE + "AND" + SPACE + val2);
                if (index != betweenLength - 1)
                    tempBetwnneSql.append(SPACE + "AND" + SPACE);
                index++;
            }
            buildSql(tempBetwnneSql.toString());
        }
        //进入isNull拼装
        if (Obj.notNullOrEmpty(condition.getNulls())) {
            for (Map.Entry<String, Boolean> n : condition.getNulls().entrySet()) {
                String col = n.getKey();
                if (n.getValue())
                    buildSql(col + SPACE + "IS null");
                else
                    buildSql(col + SPACE + "IS NOT null");
                isFirst = false;
            }
        }
        //进入GroupBy拼装
        if (Obj.notNullOrEmpty(condition.getGroups())) {
            StringBuffer tempGroupSql = new StringBuffer();
            tempGroupSql.append(SPACE + "GROUP BY" + SPACE);
            int groupLength = condition.getGroups().size();
            List<String> groups = condition.getGroups();
            for (int i = 0; i < groups.size(); i++) {
                tempGroupSql.append(groups.get(i) + (i == groupLength - 1 ? "" : ","));
            }
            buildSql(tempGroupSql.toString(), false);
        }
        //进入OrderBy拼装
        if (Obj.notNullOrEmpty(condition.getSorts())) {
            String sortType = condition.getSort().getValue();
            StringBuffer tempSortSql = new StringBuffer();
            tempSortSql.append(SPACE + "ORDER BY" + SPACE);
            int orderLength = condition.getSorts().size();
            List<String> sorts = condition.getSorts();
            for (int i = 0; i < sorts.size(); i++) {
                tempSortSql.append(sorts.get(i) + (i == orderLength - 1 ? SPACE + sortType : ","));
            }
            conditionSql += tempSortSql.toString();
        }
        if (type == ConditionHelper.InterceptorType.SEARCH) {
            // 对Mysql分页SQL的拆分
            String realSql = sqlSource.replace(" limit ?,?", "");
            sqlSource = sqlSource.replace(realSql, realSql + conditionSql);
            // }
        } else {

            sqlSource += conditionSql;
        }
        ReflectUtil.setFieldValue(boundSql, "sql", sqlSource);
        try {
            return invocation.proceed();
        } catch (Exception e) {
            return null;
        }
    }

    /*SQL拼接所需要的静态方法*/
    private String buildConnec() {
        return isFirst ? (SPACE + strWhere + SPACE) : SPACE + strAnd + SPACE;
    }

    private String buildSql(String conditionSql) {
        return buildSql(conditionSql, true);
    }

    private String buildSql(String cSql, boolean isRelation) {
        if (isRelation)
            return conditionSql += buildConnec() + cSql;
        else
            return conditionSql += cSql;
    }

    public String getConnecStr() {
        return connecStr;
    }

    public void setConnecStr(String connecStr) {
        this.connecStr = connecStr;
    }

    public String getStrAnd() {
        return strAnd;
    }

    public void setStrAnd(String strAnd) {
        this.strAnd = strAnd;
    }

    public String getStrWhere() {
        return strWhere;
    }

    public void setStrWhere(String strWhere) {
        this.strWhere = strWhere;
    }

    public IndieCondition getCondition() {
        return condition;
    }

    public void setCondition(IndieCondition condition) {
        this.condition = condition;
    }

    public ConditionHelper.InterceptorType getType() {
        return type;
    }

    public void setType(ConditionHelper.InterceptorType type) {
        this.type = type;
    }

    public BoundSql getBoundSql() {
        return boundSql;
    }

    public void setBoundSql(BoundSql boundSql) {
        this.boundSql = boundSql;
    }
    /**/

    private static class ReflectUtil {
        /**
         * 利用反射获取指定对象的指定属性
         *
         * @param obj       目标对象
         * @param fieldName 目标属性
         * @return 目标属性的值
         */
        public static Object getFieldValue(Object obj, String fieldName) {
            Object result = null;
            Field field = ReflectUtil.getField(obj, fieldName);
            if (field != null) {
                field.setAccessible(true);
                try {
                    result = field.get(obj);
                } catch (IllegalArgumentException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return result;
        }

        /**
         * 利用反射获取指定对象里面的指定属性
         *
         * @param obj       目标对象
         * @param fieldName 目标属性
         * @return 目标字段
         */
        private static Field getField(Object obj, String fieldName) {
            Field field = null;
            for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz
                    .getSuperclass()) {
                try {
                    field = clazz.getDeclaredField(fieldName);
                    break;
                } catch (NoSuchFieldException e) {
                    // 这里不用做处理，子类没有该字段可能对应的父类有，都没有就返回null。
                }
            }
            return field;
        }

        /**
         * 利用反射设置指定对象的指定属性为指定的值
         *
         * @param obj        目标对象
         * @param fieldName  目标属性
         * @param fieldValue 目标值
         */
        public static void setFieldValue(Object obj, String fieldName,
                                         String fieldValue) {
            Field field = ReflectUtil.getField(obj, fieldName);
            if (field != null) {
                try {
                    field.setAccessible(true);
                    field.set(obj, fieldValue);
                } catch (IllegalArgumentException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

}